//
//  JSViewController.m
//  JSPhotoSDK
//
//  Created by shan on 2017/5/28.
//  Copyright © 2017年 shan. All rights reserved.
//

#import "JSViewController.h"
#import <Photos/Photos.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import "JSTableViewCell.h"
#import "IJSImagePickerController.h"
#import "IJSImageAPIManager.h"
#import "IJSImageManager.h"
#import "IJSAlbumModel.h"
#import "IJSAssetModel.h"
static NSString *const cellID = @"cellid";


@interface JSViewController () <UITableViewDelegate, UITableViewDataSource, UIImagePickerControllerDelegate, UINavigationControllerDelegate, IJSImagePickerControllerDelegate>
/* 参数说明 */
@property (nonatomic, weak) UITableView *myTableview;
/* 参数说明 */
@property (nonatomic, strong) NSArray *nameArr;
/* 参数说明 */
@property (nonatomic, strong) UIImagePickerController *picker;
/* 图片 */
@property (nonatomic, strong) NSMutableArray *imageBack;

@end


@implementation JSViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self createTableViewUI];
    self.nameArr = @[ @"获取照片", @"", @"", @"", @"", @"", @"" ];
    self.imageBack = [NSMutableArray array];


    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

    //    [self getAllSourceFromPhotoLibraryWithOptions];  //获取所有资源
    //    [self textMyTest];
    //    [self selectImage];

    //    [self getAllSourceFromPhotoLibrary:^(UIImage * _Nullable result, NSDictionary * _Nullable info) {
    //        NSLog(@"---result---%@",result);
    //        NSLog(@"---info---%@",info);
    //        [self.imageBack addObject:result];
    //        [self.myTableview reloadData];
    //    }];
    //    [self getAllSourceFromPhotoLibrary:^(NSMutableArray *resultArr) {
    //        NSLog(@"-------%lu",(unsigned long)resultArr.count);
    //    }];


    //    [[IJSImageAPIManager shareManager]getAllAssetFromSourceType:PHAssetSourceTypeUserLibrary sortDescriptors:YES isAllowPickingImage:YES isAllowPickingVideo:YES isAllowPickingAudio:YES isAllowPickingGif:YES includeHiddenAssets:YES includeAllBurstAssets:YES fetchLimit:0 completion:^(NSMutableArray *result) {
    //        for (PHAsset *objc in result)
    //        {
    //            [self.imageBack addObject:objc];
    //        }
    //        [self.myTableview reloadData];
    //    }];
}

- (void)createTableViewUI
{
    UITableView *tableview = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
    [self.view addSubview:tableview];

    tableview.delegate = self;
    tableview.dataSource = self;
    [tableview registerClass:[UITableViewCell class] forCellReuseIdentifier:cellID];
    self.myTableview = tableview;
    _myTableview.rowHeight = 80;
    [self.myTableview registerClass:[JSTableViewCell class] forCellReuseIdentifier:@"cell"];
}
#pragma mark Tableview 代理方法
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (self.imageBack.count == 0) {
        return 10;
    } else {
        NSLog(@"--总数---%lu", (unsigned long)self.imageBack.count);
        return self.imageBack.count;
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    JSTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
    if (self.imageBack.count == 0) {
        return cell;
    }
    cell.asset = self.imageBack[indexPath.row];
    return cell;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    IJSImagePickerController *vc = [[IJSImagePickerController alloc] initWithMaxImagesCount:2 delegate:self];

    vc.didFinishUserPickingImageHandle = ^(NSArray<UIImage *> *photos, NSArray *avPlayers, NSArray *assets, NSArray<NSDictionary *> *infos, BOOL isSelectOriginalPhoto) {

        NSLog(@"--2----%@", avPlayers.firstObject);
        NSLog(@"----3----%@", infos);
    };


    [self presentViewController:vc animated:YES completion:nil];

    //    [[IJSImageManager shareManager] getCameraRollAlbumContentImage:YES contentVideo:YES completion:^(IJSAlbumModel *model) {
    //
    //        [[IJSImageManager shareManager] getAssetsFromFetchResult:model.result allowPickingVideo:YES allowPickingImage:YES completion:^(NSArray<IJSAssetModel *> *models) {
    //
    //
    //            [[IJSImageManager shareManager]deleteAssetArr:@[models.firstObject.asset] completion:^(id assetCollection, NSError *error, BOOL isExistedOrIsSuccess) {
    //
    //                NSLog(@"-----we---%@",error);
    //                NSLog(@"-----ko---%d",isExistedOrIsSuccess);
    //
    //            }];
    //
    //
    //
    //        }];
    //
    //    }];
}


#pragma mark phototKit

#pragma mark-----------------查---------------------------

#pragma mark PHObject
/*
 PHObject
 Photos 框架中的根类PHObject只有一个公开接口localIdentifier,是对象唯一唯一标志符.PHObject实现了-isEqual 和-hash方法.可以直接使用localIdentifier属性对PHObject及其子类对象进行对比是否同一个对象
 */

#pragma mark PHAsset.h
/*-----------------------------------PHAsset-------------------------------------------------------*/
/*
 // PHAsset.h
 PHObject
 1 PHAsset 
 代表系统的一个图片，视频或者Live Photo
 [1] mediaType :资源类型,图片或者音频或视频
 PHAssetMediaTypeUnknown = 0,
 PHAssetMediaTypeImage   = 1,
 PHAssetMediaTypeVideo   = 2,
 PHAssetMediaTypeAudio   = 3,
 
 [2] mediaSubtypes
 图片又包含全景图(Panorama)、HDR图片、屏幕截图、livePhoto .live photo 加3Dtouch效果 我们可以使用照片资源的 mediaSubtypes 属性验证资源库中的图像在捕捉时是否开启了 HDR，拍摄时是否使用了相机应用的全景模式
 
 PHAssetMediaSubtypeNone      = 0,
 
 // Photo subtypes
 PHAssetMediaSubtypePhotoPanorama
 PHAssetMediaSubtypePhotoHDR
 PHAssetMediaSubtypePhotoScreenshot
 PHAssetMediaSubtypePhotoLive
 PHAssetMediaSubtypePhotoDepthEffect
 
 // Video subtypes
 PHAssetMediaSubtypeVideoStreamed      = (1UL << 16),
 PHAssetMediaSubtypeVideoHighFrameRate = (1UL << 17),
 PHAssetMediaSubtypeVideoTimelapse
 
 [3] pixelWidth 像素宽度 pixelHeight 高度
 
 [4] creationDate 创建时间   modificationDate 修改时间  location 位置信息 duration时长
 
 [5] hidden 要验证一个资源是否被用户标记为收被隐藏，只要检查 PHAsset 实例的 hidden 属性即可。
 [6] Favorite  布尔值，用户是否标记资源为"收藏"，我们平时浏览照片或视频，在下方点💗就表示收藏这张图
 
 [7] representsBurst 和 burstSelectionTypes: 对于一个资源，如果其 PHAsset 的 representsBurst 属性为 true，则表示这个资源是一系列连拍照片中的代表照片 (多张照片是在用户按住快门时拍摄的)。它还有一个属性是 burstIdentifier，如果想要获取连拍照片中的剩余的其他照片，可以通过将这个值传入 fetchAssetsWithBurstIdentifier(...) 方法来获取。用户可以在连拍的照片中做标记；此外，系统也会自动用各种试探来标记用户可能会选择的潜在代表照片。这个元数据是可以通过 PHAsset 的 burstSelectionTypes 属性来访问。这个属性是用三个常量组成的位掩码：.UserPick 表示用户手动标记的资源，.AutoPick 表示用户可能标记的潜在资源，.None 表示没有标记的资源
 
 [8] localIdentifier Photos 框架中的根类PHObject只有一个公开接口localIdentifier,是对象唯一唯一标志符.PHObject实现了-isEqual 和-hash方法.可以直接使用localIdentifier属性对PHObject及其子类对象进行对比是否同一个对象
 
 方法
 // 可执行编辑操作
 - (BOOL)canPerformEditOperation:(PHAssetEditOperation)editOperation;
*/

/*-----------------------------------PHCollection.h-------------------------------------------------------*/
#pragma mark PHCollection.h
/*
 // PHCollection
 1, PHCollection :一个抽象类，是PHAssetCollection和PHColletionList的父类
 [1.1] localizedTitle 标题
 
 2 ,  PHAssetCollection 相册(PHAsset集合)
 PHAssetCollection是一组有序的资源集合,包括相册、moments、智能相册以及共享照片流.比如：系统相册里的时刻一个分类，用户创建的相册或者智能相册
 
 [2.1] assetCollectionType  资源集合类型，比如相册或者“时刻”相册
 PHAssetCollectionTypeAlbum      = 1,      // 用户相册
 PHAssetCollectionTypeSmartAlbum = 2,  // 智能相册
 PHAssetCollectionTypeMoment     = 3,     // 时刻”相册
 
 [2.2] assetCollectionSubtype 子类型
 enum PHAssetCollectionType : Int {
 case Album             //从 iTunes 同步来的相册，以及用户在 Photos 中自己建立的相册
 case SmartAlbum    //经由相机得来的相册
 case Moment            //Photos 为我们自动生成的时间分组的相册
 }
 
 enum PHAssetCollectionSubtype : Int
 {
 PHAssetCollectionSubtypeSmartAlbumSlomoVideos
 PHAssetCollectionSubtypeSmartAlbumSelfPortraits
 PHAssetCollectionSubtypeSmartAlbumScreenshots
 PHAssetCollectionSubtypeSmartAlbumDepthEffect
 PHAssetCollectionSubtypeSmartAlbumLivePhotos
 // Used for fetching, if you don't care about the exact subtype
 PHAssetCollectionSubtypeAny = NSIntegerMax
 
 case PHAssetCollectionSubtypeAlbumRegular              //用户在 Photos 中创建的相册
 case PHAssetCollectionSubtypeAlbumSyncedEvent      //使用 iTunes 从 Photos 照片库或者 iPhoto 照片库同步过来的事件。然而，在iTunes 12 以及iOS 9.0 beta4上，选用该类型没法获取同步的事件相册，而必须使用AlbumSyncedAlbum。
 case PHAssetCollectionSubtypeAlbumSyncedFaces      //使用 iTunes 从 Photos 照片库或者 iPhoto 照片库同步的人物相册。
 case PHAssetCollectionSubtypeAlbumSyncedAlbum          //从iPhoto同步到设备的相册
 case PHAssetCollectionSubtypeAlbumImported                 //从相机或是外部存储导入的相册，完全没有这方面的使用经验，没法验证。
 
 case PHAssetCollectionSubtypeAlbumMyPhotoStream    //用户的 iCloud 照片流
 case PHAssetCollectionSubtypeAlbumCloudShared          //用户使用 iCloud 共享的相册
 case PHAssetCollectionSubtypeSmartAlbumGeneric        //文档解释为非特殊类型的相册，主要包括从 iPhoto 同步过来的相册。
 case PHAssetCollectionSubtypeSmartAlbumPanoramas   //相机拍摄的全景照片
 case PHAssetCollectionSubtypeSmartAlbumVideos          //相机拍摄的视频
 case PHAssetCollectionSubtypeSmartAlbumFavorites       //收藏文件夹
 case PHAssetCollectionSubtypeSmartAlbumTimelapses      //延时视频文件夹，同时也会出现在视频文件夹中
 case PHAssetCollectionSubtypeSmartAlbumAllHidden       //包含隐藏照片或视频的文件夹
 case PHAssetCollectionSubtypeSmartAlbumRecentlyAdded //相机近期拍摄的照片或视频
 case PHAssetCollectionSubtypeSmartAlbumBursts                  //连拍模式拍摄的照片
 case PHAssetCollectionSubtypeSmartAlbumUserLibrary  //这个命名最神奇了，就是相机相册，所有相机拍摄的照片或视频都会出现在该相册中，而且使用其他应用保存的照片也会出现在这里,用户创建出来的
 case Any //包含所有类型
 }
 
 [2.3] startDate endDate 开始 结束时间
 
 [2.4] estimatedAssetCount ：估算的asset数量，不精确
 
 [2.5] CLLocation *approximateLocation;  大概的位置
 [2.6] NSArray<NSString *> *localizedLocationNames; 位置地区的名字数组
 
 
 
 
 3, PHCollectionList : 相册集合, 比如：时刻里的年或者包含用户创建的一个或者多个相册
 表示一组PHCollection,而它本身也是一个PHCollection,因此PHCollection作为一个集合，可以包含其他集合
 [3.1] collectionListType
 [3.2] collectionListSubtype
 [3.3] startDate
 [3.4 ]endDate
 */

// 获取模型数据
//PHAsset 、PHCollection、PHCollectionList有一系列类方法可供我们访问资源的元数据
/*
 1, 比如PHAsset提供了一系列获取PHAsset对象的方法
 + fetchAssetsInAssetCollection:options:
 + fetchAssetsWithMediaType:options:
 + fetchAssetsWithLocalIdentifiers:options:
 + fetchKeyAssetsInAssetCollection:options:
 + fetchAssetsWithOptions:
 + fetchAssetsWithBurstIdentifier:options:
 + fetchAssetsWithALAssetURLs:options:
 其中fetchAssetsInAssetCollection:options：方法可以获取资源集合中的所有asset对象。每个方法中的 PHFetchOptions参数，是获取asset对象的一些配置，我们可以设置获取asset的条件,比如获取哪种资源，如何分类。获取的时候，如果该参数为空，则使用系统的默认值，当我们调用如上所示方法获取时，可以直接传nil
 */


/*-----------------------------------PHFetchOptions-------------------------------------------------------*/
#pragma mark PHFetchOptions
/*
 
 PHFetchOptions

 PHFetchOptions : option的集合，对asset对象进行  过滤，排序和管理
 [1] predicate 做选择的约束条件。比如，只获取图片，不获取视频。指定 PHAssetMediaType为image.
 
 [2]  sortDescriptors 可指定字段用来对获取结果进行排序
 
 [3] includeHiddenAssets 获取结果是否包括被隐藏的资源
 
 [4] includeAllBurstAssets 获取结果是否包括连拍资源
 
 [5] includeAssetSourceTypes 资源的来源
 PHAssetSourceTypeNone
 PHAssetSourceTypeUserLibrary
 PHAssetSourceTypeCloudShared
 PHAssetSourceTypeiTunesSynced
 
 [6] fetchLimit  搜索结果的限制 ,0 表示无限制
 
 [7] wantsIncrementalChangeDetails ,搜索结果细节变化
 
 */

/*-----------------------------------PHFetchResult.h-------------------------------------------------------*/
#pragma mark PHFetchResult
/*
 PHFetchResult
 PHFetchResult: 类似数组,包含assets或者collections有序的一系列集合
 同步快速获取结果,
 即使结果集很大，框架也能保证获取速度. 因为它不会一次性将所有结果放进内存，而是按需批量加载
 可以用类似 NSArray 的接口来访问PHFetchResult结果内的集合
 提供快速枚举的方法
 - (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(ObjectType obj, NSUInteger idx, BOOL *stop))block;
 就算满足请求的照片库内容发生了改变，获取方法所返回的 PHFetchResult 对象是不会自动更新。在后面的小节中，我们会介绍如何对返回的 PHFetchResult 对象的改变进行观察并处理更新内容。
 可以借助 PHObjectChangeDetails 或 PHFetchResultChangeDetails 对象来观察这些变化
 */
#pragma mark------------------------增 删 改---------------------------------
/*-----------------------------------PHImageManager.h-------------------------------------------------------*/

#pragma mark PHImageManager
/*
 --------PHImageManager------------
 在框架中是个单例对象，用[PHImageManager defaultManager]获取,它提供了加载图片和视频的方法,解析 PHAsset 资源

 注释翻译:
 
 如果获取的资源的宽高比不符合, contentMode 决定现实的大小
 PHImageContentModeAspectFit:  等比例适应
 PHImageContentModeAspectFill:  等比例缩放适应
 PHImageContentModeDefault = PHImageContentModeAspectFit  默认值
 [PHImageRequestOptions isSynchronous] returns NO (or options is nil), resultHandler 可能会请求多次
 deliveryMode = PHImageRequestOptionsDeliveryModeOpportunistic
 默认情况下，这些API是异步执行，但是我们可以通过options参数中的synchronous属性，设置为同步执行，这些方法会阻塞当前调用线程直到下载完成或者发生错误
 请求取消将不再返回 resultHandler
 
 方法注释:
 asset:   需要解析的资源
 targetSize: 需要获取的图像的尺寸，如果输入的尺寸大于资源原图的尺寸，则只返回原图。需要注意在 PHImageManager 中，所有的尺寸都是用 Pixel 作为单位（Note that all sizes are in pixels），因此这里想要获得正确大小的图像，需要把输入的尺寸转换为 Pixel。如果需要返回原图尺寸，可以传入 PhotoKit 中预先定义好的常量?PHImageManagerMaximumSize，表示返回可选范围内的最大的尺寸，即原图尺寸
 contentMode: 图像的剪裁方式,控制照片应该以按比例缩放还是按比例填充的方式放到最终展示的容器内。注意如果 targetSize 传入PHImageManagerMaximumSize，则 contentMode 无论传入什么值都会被视为 PHImageContentModeDefault
 options: PHImageRequestOptions 的实例，可以控制的内容相当丰富，包括图像的质量、版本，也会有参数控制图像的剪裁
 resultHandler: 请求结束后被调用的 block，返回一个包含资源对于图像的 UIImage 和包含图像信息的一个 NSDictionary，在整个请求的周期中，这个 block 可能会被多次调用
 
 - (PHImageRequestID)requestImageForAsset:(PHAsset *)asset targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options resultHandler:(void (^)(UIImage *__nullable result, NSDictionary *__nullable info))resultHandler;
 请求大图 ,回调只执行一次,deliveryMode直接被忽略,设置了PHImageRequestOptionsVersionCurrent 并且资源被调整过,则返回最大的图
 - (PHImageRequestID)requestImageDataForAsset:(PHAsset *)asset options:(nullable PHImageRequestOptions *)options resultHandler:(void(^)(NSData *__nullable imageData, NSString *__nullable dataUTI, UIImageOrientation orientation, NSDictionary *__nullable info))resultHandler;
 
 // 取消请求
 - (void)cancelImageRequest:(PHImageRequestID)requestID;
 
 ------------PHImageRequestOptions:----------------------
 中包含了一系列控制请求图像的属性
 如果resizeMode所控制的剪裁结果有所冲突，PhotoKit 会以 resizeMode 的结果为准

 1,  PHImageRequestOptionsVersion version:
 这个属性是指获取的图像是否需要包含系统相册“编辑”功能处理过的信息（如滤镜，旋转等）
 图片编辑extension，可以根据次枚举获取原图或者是经编辑过的图片
 PHImageRequestOptionsVersionCurrent = 0, //当前的(编辑过?经过编辑的图：原图)
 PHImageRequestOptionsVersionUnadjusted, //经过编辑的图
 PHImageRequestOptionsVersionOriginal       //原始图片
 
  2, PHImageRequestOptionsDeliveryMode deliveryMode:
 则用于控制请求的图片质量
 PHImageRequestOptionsDeliveryModeOpportunistic:在速度与质量中均衡 根据我options.synchronous判断返回结果是一个或多个
 PHImageRequestOptionsDeliveryModeHighQualityFormat 制定的同步返回一个结果，返回的图片质量是比我们设定的size会好一点(实际上与PHImageRequestOptions的resizeMode枚举相关) 高质量图
 PHImageRequestOptionsDeliveryModeFastFormat 仅返回一次，效率较高之余获得的图质量不太好,速度最快
 
 
  3, PHImageRequestOptionsResizeMode resizeMode:  PHImageRequestOptionsResizeModeNone (or no resize)无效 属性控制图像的剪裁
  
 4 CGRect normalizedCropRect: 用于对原始尺寸的图像进行裁剪，基于比例坐标。只在 resizeMode 为 Exact 时有效
 5 BOOL networkAccessAllowed; 是否允许从 icloud请求资源 另一个和 iCloud 相关的属性是 progressHandler。你可以将它设为一个PHAssetImageProgressHandler 的 block，当从 iCloud 下载照片时，它就会被图像管理器自动调用
 6 BOOL synchronous 是否为同步操作，默认为NO，如果设置为YES则，相关模式下只会返回一张图片
  PHAssetImageProgressHandler progressHandler 当图像需要从 iCloud 下载时，这个 block 会被自动调用，block 中会返回图像下载的进度，图像的信息，出错信息。开发者可以利用这些信息反馈给用户当前图像的下载进度以及状况，但需要注意?progressHandler 不在主线程上执行，因此在其中需要操作 UI，则需要手工放到主线程执行
 上面有提到，requestImageForAsset 中的参数?resultHandler 可能会被多次调用，这种情况就是图像需要从 iCloud 中下载的情况。在?requestImageForAsset 返回的内容中，一开始的那一次请求中会返回一个小尺寸的图像版本，当高清图像还在下载时，开发者可以首先给用户展示这个低清的图像版本，然后 block 在多次调用后，最终会返回高清的原图。至于当前返回的图像是哪个版本的图像，可以通过 block 返回的 NSDictionary info 中获知，PHImageResultIsDegradedKey 表示当前返回的 UIImage 是低清图。如果需要判断是否已经获得高清图，可以这样判断：
 
 BOOL downloadFinined = (![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey]);
 
 requestImageForAsset 发出对图像的请求时，如果在同一个 PHImageManager 中同时对同一个资源发出图像请求，请求的进度是可以共享的，因此我们可以利用这个特性，把 PHImageManager 以单例的形式使用，这样在切换界面时也不用担心无法传递图像的下载进度。例如，在图像的列表页面触发了下载图像，当我们离开列表页面进入预览大图界面时，并不用担心会重新图像会重新下载，只要没有手工取消图像下载，进入预览大图界面下载图像会自动继续从上次的进度下载图像

 ------------PHLivePhotoRequestOptions:----------------------
  PHImageRequestOptionsVersion version;
  PHImageRequestOptionsDeliveryMode deliveryMode;
  BOOL networkAccessAllowed;
  PHAssetImageProgressHandler progressHandler;
 
 
  ------------PHVideoRequestOptions:----------------------
  BOOL networkAccessAllowed;
  PHVideoRequestOptionsVersion version;
 PHVideoRequestOptionsDeliveryMode deliveryMode;
 PHAssetVideoProgressHandler progressHandler;
// 获取
 - (PHImageRequestID)requestPlayerItemForVideo:(PHAsset *)asset options:(nullable PHVideoRequestOptions *)options resultHandler:(void (^)(AVPlayerItem *__nullable playerItem, NSDictionary *__nullable info))resultHandler;
 // 导出
 - (PHImageRequestID)requestAVAssetForVideo:(PHAsset *)asset options:(nullable PHVideoRequestOptions *)options resultHandler:(void (^)(AVAsset *__nullable asset, AVAudioMix *__nullable audioMix, NSDictionary *__nullable info))resultHandler;
 
 */

/*-----------------------------------PHPhotoLibrary.h-------------------------------------------------------*/
#pragma mark PHPhotoLibrary
/*
 // 协议 :
 PHPhotoLibraryChangeObserver:
 PHPhotoLibraryChangeObserver 协议能让我们知道照片相册库中的改变。Photos会发送系统图片改变的消息，我们可以遵守PHPhotoLibraryChangeObserver协议，并通过 PHPhotoLibrary的registerChangeObserver方法将对象注册为观察者，时时接收照片改变的消息。
 // 串行队列 相册数据改变 知道照片相册库中的改变
 - (void)photoLibraryDidChange:(PHChange *)changeInstance;
 
 PHPhotoLibrary:

 系统中PHPhotoLibrary单例对象 是用来维护用户照片库。当我们需要编辑资源对象元数据、资源内容、或者插入新的资源对象等，都可以借助通过PHPhotoLibrary单例对象执行block，block中创建我们指定的请求对象(比如PHAssetChangeRequest,PHAssetCollectionChangeRequest, PHCollectionListChangeRequest的对象)。photoLibraryDidChange(changeInfo: PHChange!)中进行.
 {
 PHAuthorizationStatusNotDetermined = 0, // 未选择
 PHAuthorizationStatusRestricted,        // 用户受到某些限制，不能自己决定，比如：家长控制
 PHAuthorizationStatusDenied,            // 用户明确拒绝
 PHAuthorizationStatusAuthorized         // 已经授权
 }

 // 单利初始化
 + (PHPhotoLibrary *)sharedPhotoLibrary;
 //判断授权
 + (PHAuthorizationStatus)authorizationStatus;
 请求授权
 + (void)requestAuthorization:(void(^)(PHAuthorizationStatus status))handler;
 
 //  执行同步和异步数据
 - (void)performChanges:(dispatch_block_t)changeBlock completionHandler:(nullable void(^)(BOOL success, NSError *__nullable error))completionHandler;
 - (BOOL)performChangesAndWait:(dispatch_block_t)changeBlock error:(NSError *__autoreleasing *)error;
 
 // 将对象注册为观察者，时时接收照片改变的消息。
 - (void)registerChangeObserver:(id<PHPhotoLibraryChangeObserver>)observer;
 - (void)unregisterChangeObserver:(id<PHPhotoLibraryChangeObserver>)observer;
 
 */
/*-----------------------------------PHChange.h-------------------------------------------------------*/
#pragma mark PHChange
/*
 1, PHChange:NSObject
 
 PHphoto框架会提供给我们PHChange对象，我们可以调用changeDetailsForObject或者changeDetailsForFetchResult 方法，它返回给我们一个PHObjectChangeDetails对象，是对最新的照片实体对象的引用，可以告诉我们对象的图像数据是否曾变化过、对象是否曾被删除过
 - (nullable PHObjectChangeDetails *)changeDetailsForObject:(PHObject *)object;
 - (nullable PHFetchResultChangeDetails *)changeDetailsForFetchResult:(PHFetchResult *)object;
 
 2, PHObjectChangeDetails:NSObject
 提供了一个对最新的照片实体对象的引用，以及告诉你对象的图像数据是否曾变化过、对象是否曾被删除过的布尔值
 // 泛型类<PHObject>照片改变之前的状态,  解析changeDetailsForObject方法返回的对象
 2.1 __kindof ObjectType objectBeforeChanges;
 // 改变之后的状态
  2.2__kindof ObjectType objectAfterChanges;
 // 如果该对象的图像或视频内容已更改则返回YES
  2.3 BOOL assetContentChanged;
 // 对象被删除则返回 YES
  2.4 BOOL objectWasDeleted;
 
 3, PHFetchResultChangeDetails
 处理之前获取的 PHFetchResult 上的变化的信息。PHFetchResultChangeDetails 是为了尽可能简化 CollectionView 或 TableView 的更新操作而设计的。它的属性恰好映射到你在使用一个典型的 CollectionView 的 update handler 时所需要的信息。注意，若要正确的更新 UITableView/UICollectionView，你必须以正确顺序来处理变化，那就是：RICE —— removedIndexes，insertedIndexes，changedIndexes，enumerateMovesWithBlock (如果 hasMoves 为 true 的话)。另外，PHFetchResultChangeDetails 的 hasIncrementalChanges 属性可以被设置成 false，这意味着旧的获取结果应该全部被新的值代替。这种情况下，你应该调用 UITableView/UICollectionView 的 reloadData。
 
 注意：没有必要以集中的方式处理变化。如果你应用中的多个组件需要处理照片实体，那么它们每个都要有自己的 PHPhotoLibraryChangeObserver 。接着组件就能靠自己查询 PHChange 对象，检测是否需要 (以及如何) 更新它们自己的状态
 
 // 资源改变之前的状态
 3.1  PHFetchResult<ObjectType> *fetchResultBeforeChanges;
 
 // 资源改变之后的状态
 3.2 PHFetchResult<ObjectType> *fetchResultAfterChanges;
 
 // 资源操作包括 移除/插入/改变细节 则返回 YES
 // 不指明改变的范围或者UI重载则无法提供数据
 3.3 BOOL hasIncrementalChanges;
 
 // 在 'before' 状态前, 移除索引
 // 如果 hasIncrementalChanges 是 NO  returns nil
  3.4 NSIndexSet *removedIndexes;
  3.5 NSArray<ObjectType> *removedObjects;
 
 // 插入元素, 和 3.4 / 3.5 相似
  3.6 NSIndexSet *insertedIndexes;
  3.7 NSArray<ObjectType> *insertedObjects;
 
 // 改变元素
  3.8 NSIndexSet *changedIndexes;
  3.9 NSArray<ObjectType> *changedObjects;
 
 
 // 包括 moved items 就返回 YES
 // returns NO if hasIncrementalChanges is NO
 3.10  BOOL hasMoves;
 
 // 在 removedIndexes and insertedIndexes 这俩状态之后快速枚举资源下标
 - (void)enumerateMovesWithBlock:(void(^)(NSUInteger fromIndex, NSUInteger toIndex))handler;
 
 // Provides a "diff" between 2 PHFetchResult objects.
 + (instancetype)changeDetailsFromFetchResult:(PHFetchResult<ObjectType> *)fromResult toFetchResult:(PHFetchResult<ObjectType> *)toResult changedObjects:(NSArray<ObjectType> *)changedObjects;
 
 必须以正确顺序来处理变化：RICE —— removedIndexes，insertedIndexes，changedIndexes，enumerateMovesWithBlock (如果 hasMoves 为 true 的话)
 
 */

/*-----------------------------------PhotosTypes.h-------------------------------------------------------*/
#pragma mark PhotosTypes
/*
 // PHCollectionListTypeMomentList的子类型
 PHCollectionListSubtypeMomentListCluster     // 时刻
 PHCollectionListSubtypeMomentListYear         // 年度
 
 // PHCollectionListTypeFolder的子类型
 PHCollectionListSubtypeRegularFolder            // 包含了其他文件夹或者相簿的文件夹
 
 // PHCollectionListTypeSmartFolder的子类型
 PHCollectionListSubtypeSmartFolderEvents     // 包含了一个或多个从iPhone同步的事件的智能文件夹
 PHCollectionListSubtypeSmartFolderFaces      // 包含了一个或多个从iPhone同步的面孔（人物）的智能文件夹
 98噶前ui-0
 // 如果你不关心子类型是什么，则使用下面这个
 PHCollectionListSubtypeAny = NSIntegerMax
 */

- (void)getAssetFromPhAsset
{
    PHFetchOptions *allPhotosOptions = [[PHFetchOptions alloc] init];
    // 按图片生成时间排序
    allPhotosOptions.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES] ];
    // 获取图片
    PHFetchResult *allPhotos = [PHAsset fetchAssetsWithOptions:allPhotosOptions];
    // 获取智能相册
    PHFetchResult *smartAlbums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAlbumRegular options:nil];
    // 获取用户创建的相册
    PHFetchResult *topLevelUserCollections = [PHCollectionList fetchTopLevelUserCollectionsWithOptions:nil];
}


//   获取所有的资源
- (void)getAllSourceFromPhotoLibrary:(void (^)(NSMutableArray *resultArr))resultHandler
{
    NSMutableArray *resultArr = [NSMutableArray array];
    //  PHAsset 查询 条件
    PHFetchOptions *foptions = [[PHFetchOptions alloc] init];

    //    foptions.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d || mediaType == %d",7,PHAssetMediaTypeImage];  // 包含图片是视频

    foptions.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d", 10]; // 只获取图片
    //    foptions.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d",PHAssetMediaTypeAudio];  // 只获取图片
    foptions.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES] ];
    foptions.includeHiddenAssets = YES;                              // 收藏
    foptions.includeAllBurstAssets = YES;                            // 包括连拍
    foptions.includeAssetSourceTypes = PHAssetSourceTypeUserLibrary; // 相册来源
    foptions.fetchLimit = 1000;                                      // 最大可选数量
    foptions.wantsIncrementalChangeDetails = YES;                    //包含细节
    // 查询
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        PHFetchResult<PHAsset *> *result = [PHAsset fetchAssetsWithOptions:foptions];
        for (PHAsset *asset in result) {
            [resultArr insertObject:asset atIndex:0];
        }
        resultHandler(resultArr);
    });
}

- (void)requestVideoFromAsset:(PHAsset *)asset resultHandler:(void (^)())resultHandler
{
    [[PHImageManager defaultManager] requestPlayerItemForVideo:asset options:nil resultHandler:^(AVPlayerItem *_Nullable playerItem, NSDictionary *_Nullable info){


    }];
}

#pragma mark 系统根据时间段生成的相册集合 手机上照片的位置
- (void)getCollectionList
{
    PHFetchResult<PHCollectionList *> *list = [PHCollectionList fetchMomentListsWithSubtype:PHCollectionListSubtypeMomentListCluster options:nil];
    [list enumerateObjectsUsingBlock:^(PHCollectionList *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
        NSLog(@"--PHCollectionList---%@", obj);
    }];
}


#pragma mark 授权
- (void)isAuthouorizationStatus
{
    NSLog(@"---授权--%ld", (long)[PHPhotoLibrary authorizationStatus]);
    [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
        NSLog(@"-授权状态----%ld", (long)status);
    }];
}
#pragma mark 根据约束条件获取所有的资源
- (void)getAllSourceFromPhotoLibraryWithOptions
{
    // 约束条件
    PHFetchOptions *options = [[PHFetchOptions alloc] init];
    options.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d", PHAssetMediaTypeImage];       // 只获取图片
    options.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES] ]; // 按图片生成时间排序
    options.includeHiddenAssets = YES;                                                                     // 获取结果是否包括被隐藏的资源
    options.includeAllBurstAssets = YES;                                                                   // 获取结果是否包括连拍资源
    options.includeAssetSourceTypes = PHAssetSourceTypeUserLibrary;                                        // 资源的来源包括 资源的来源
    options.fetchLimit = 0;                                                                                // 搜索结果的限制 ,0 表示无限制
    options.wantsIncrementalChangeDetails = YES;                                                           // 查看细节
    //   搜索所有的资源
    PHFetchResult<PHAsset *> *allPhotos = [PHAsset fetchAssetsWithOptions:options]; //获取所有资源

    [allPhotos enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
        // 将资源解析成为可用资源
        [[PHImageManager defaultManager] requestImageForAsset:obj targetSize:CGSizeMake(0, 0) contentMode:PHImageContentModeDefault options:nil resultHandler:^(UIImage *_Nullable result, NSDictionary *_Nullable info) {
            [self.imageBack addObject:result];
            [self.myTableview reloadData];
        }];
    }];
}
#pragma mark 获取用户自己创建的相册
- (void)getUserAlbum
{
    PHFetchResult<PHAssetCollection *> *ass = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeAny options:nil];
    [ass enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
        NSLog(@"--PHAssetCollection---%@", obj);
    }];
}
#pragma mark 获取系统创建的相册
- (void)getSystemAlbum
{
    PHFetchResult<PHAssetCollection *> *ass = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeSmartAlbum subtype:PHAssetCollectionSubtypeAny options:nil];
    [ass enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
        NSLog(@"--PHAssetCollection---%@", obj);
    }];
}
#pragma mark 获取根据时间创建的相册
- (void)getMomentAlbum
{
    PHFetchResult<PHAssetCollection *> *ass = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeMoment subtype:PHAssetCollectionSubtypeAny options:nil];
    [ass enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
        NSLog(@"--PHAssetCollection---%@", obj);
    }];
}

- (void)getAssetFromPhAssetPHFetchOptions
{
    PHFetchOptions *options = [[PHFetchOptions alloc] init];
    options.wantsIncrementalChangeDetails = YES;
    options.includeAllBurstAssets = YES;
    options.includeHiddenAssets = YES;
    // 只取图片
    options.predicate = [NSPredicate predicateWithFormat:@"mediaType == %d", PHAssetMediaTypeImage];
    // 按时间排序
    options.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES] ];

    PHFetchResult *albums = [PHAssetCollection fetchAssetCollectionsWithType:PHAssetCollectionTypeAlbum subtype:PHAssetCollectionSubtypeSmartAlbumAllHidden options:nil];
    NSLog(@"--1---%@", albums);
}


- (void)selectImage
{
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
        NSLog(@"支持相机");
    }
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
        NSLog(@"支持图库");
    }
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeSavedPhotosAlbum]) {
        NSLog(@"支持相片库");
    }

    if ([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear]) {
        NSLog(@"后置摄像头能用");
    }
    if ([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront]) {
        NSLog(@"前置摄像头能用");
    }
    // 指定摄像头的闪光灯是否可用
    if ([UIImagePickerController isFlashAvailableForCameraDevice:UIImagePickerControllerCameraDeviceRear]) {
        NSLog(@"后置支持闪光灯flash and torch");
    }
    if ([UIImagePickerController isFlashAvailableForCameraDevice:UIImagePickerControllerCameraDeviceFront]) {
        NSLog(@"前置支持闪光灯flash and torch");
    }

    //指定的源设备上可用的媒体类型，一般就是图片和视频/判断是否支持某种多媒体类型：拍照，视频
    /*
     "public.image",
     "public.movie"
     */
    NSLog(@"--1--%@", [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypePhotoLibrary]);
    NSLog(@"--2---%@", [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera]);
    NSLog(@"--3--%@", [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeSavedPhotosAlbum]);

    /*
     获得指定摄像头上的可用捕获模式，捕获模式是枚举类型：
     UIImagePickerControllerCameraCaptureModePhoto：拍照模式
     UIImagePickerControllerCameraCaptureModeVideo：视频录制模式
     */
    NSLog(@"--4---%@", [UIImagePickerController availableCaptureModesForCameraDevice:UIImagePickerControllerCameraDeviceRear]);
    NSLog(@"--5---%@", [UIImagePickerController availableCaptureModesForCameraDevice:UIImagePickerControllerCameraDeviceFront]);

    // 判断当前的sourceType是否可用
    if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
        UIImagePickerController *imagePickerVC = [[UIImagePickerController alloc] init]; // 实例化UIImagePickerController控制器
        /*
         UIImagePickerControllerSourceTypePhotoLibrary, //所有的相册
         UIImagePickerControllerSourceTypeCamera,       // 相机
         UIImagePickerControllerSourceTypeSavedPhotosAlbum  // 按照时间排好的图库
         */
        //        imagePickerVC.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;      // 设置资源来源（相册、相机、图库之一）

        // 设置所支持的类型，设置只能拍照，或则只能录像，或者两者都可以
        // 媒体类型,默认情况下此数组包含kUTTypeImage，所以拍照时可以不用设置；但是当要录像的时候必须设置，可以设置为kUTTypeVideo（视频，但不带声音）或者kUTTypeMovie（视频并带有声音）
        /*
         kUTTypeImage  静态图片
         kUTTypeVideo 没有声音
         kUTTypeMovie 视频有声音
         */
        //        NSArray * arrMediaTypes = @[( NSString *)kUTTypeImage,( NSString *)kUTTypeMovie];
        //        [imagePickerVC setMediaTypes:arrMediaTypes];

        /*
         allowsEditing            //  允许编辑 默认是NO
         */
        //        imagePickerVC.allowsEditing = YES;

        // 如果选择的是视屏，允许的视屏时长为20秒
        //        imagePickerVC.videoMaximumDuration = 3;
        //        imagePickerVC.videoQuality = UIImagePickerControllerQualityTypeHigh; // 允许的视屏质量（如果质量选取的质量过高，会自动降低质量）

        //        imagePickerVC.showsCameraControls = YES;  //是否显示摄像头控制面板，默认为YES
        // 摄像头上覆盖的视图，可用通过这个视频来自定义拍照或录像界面
        //        imagePickerVC.cameraOverlayView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 100, 20)];
        //        imagePickerVC.cameraViewTransform = CGAffineTransformMake(0, 0, 1, 2, 3, 4);  //旋转角度

        /*
         UIImagePickerControllerCameraCaptureModePhoto：拍照模式
         UIImagePickerControllerCameraCaptureModeVideo：视频录制模式
         */
        //摄像头捕获模式，捕获模式是枚举类型
        //        imagePickerVC.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo;

        /*
         UIImagePickerControllerCameraDeviceRear：后置置摄像头
         UIImagePickerControllerCameraDeviceFront：前置摄像头
         */
        //摄像头设备，cameraDevice是枚举类型：
        //        imagePickerVC.cameraDevice = UIImagePickerControllerCameraDeviceRear;

        /*
         UIImagePickerControllerCameraFlashModeOff：关闭闪光灯
         UIImagePickerControllerCameraFlashModeAuto：闪光灯自动
         UIImagePickerControllerCameraFlashModeOn：打开闪光灯
         */
        //闪光灯模式，枚举类型：
        //        imagePickerVC.cameraFlashMode = UIImagePickerControllerCameraFlashModeAuto;

        /*
         对象方法
         */
        //        [imagePickerVC takePicture];            //编程方式拍照
        //        [imagePickerVC startVideoCapture]; //	编程方式录制视频
        //        [imagePickerVC stopVideoCapture];  //	编程方式停止录制视频


        // 设置代理，遵守UINavigationControllerDelegate, UIImagePickerControllerDelegate 协议
        imagePickerVC.delegate = self;
        // 是否允许编辑（YES：图片选择完成进入编辑模式）
        //        imagePickerVC.allowsEditing = YES;
        // model出控制器
        [self presentViewController:imagePickerVC animated:YES completion:nil];
        self.picker = imagePickerVC;
    }
}


#pragma mark UIIamgePicker 代理方法
// 媒体拾取完成
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(nullable NSDictionary<NSString *, id> *)editingInfo
{
    NSLog(@"--editingInfo---%@", editingInfo);
}
// 选择结束
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *, id> *)info
{
    NSLog(@"---info----%@", info);
    [self.picker dismissViewControllerAnimated:YES completion:nil];
}

// 当用户取消选取时调用
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
}
#pragma mark c 函数 方法
- (void)saveImageToMyAlbum
{
    void UIImageWriteToSavedPhotosAlbum(UIImage * image, id completionTarget, SEL completionSelector, void *contextInfo); //保存照片到相簿
    BOOL UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(NSString * videoPath);                                             //能否将视频保存到相簿
    void UISaveVideoAtPathToSavedPhotosAlbum(NSString * videoPath, id completionTarget, SEL completionSelector, void *contextInfo);
}


//#import <MobileCoreServices/MobileCoreServices.h>
//kUTTypeImage 包含:
/*
 NSString *const  UIImagePickerControllerMediaType ; 指定用户选择的媒体类型（文章最后进行扩展）
 NSString *const  UIImagePickerControllerOriginalImage ; 原始图片
 NSString *const  UIImagePickerControllerEditedImage ; 修改后的图片
 NSString *const  UIImagePickerControllerCropRect ;    裁剪尺寸
 NSString *const  UIImagePickerControllerMediaURL ;媒体的URL
 NSString *const  UIImagePickerControllerReferenceURL ;原件的URL
 NSString *const  UIImagePickerControllerMediaMetadata; 当来数据来源是照相机的时候这个值才有效
 */
/*
 const CFStringRef  kUTTypeAudiovisualContent ;抽象的声音视频
 const CFStringRef  kUTTypeMovie ;抽象的媒体格式（声音和视频）
 const CFStringRef  kUTTypeVideo ;只有视频没有声音
 const CFStringRef  kUTTypeAudio ;只有声音没有视频
 const CFStringRef  kUTTypeQuickTimeMovie ;
 const CFStringRef  kUTTypeMPEG ;
 const CFStringRef  kUTTypeMPEG4 ;
 const CFStringRef  kUTTypeMP3 ;
 const CFStringRef  kUTTypeMPEG4Audio ;
 const CFStringRef  kUTTypeAppleProtectedMPEG4Audio;
 */

/*
 const CFStringRef  kUTTypeImage ;抽象的图片类型
 const CFStringRef  kUTTypeJPEG ;
 const CFStringRef  kUTTypeJPEG2000 ;
 const CFStringRef  kUTTypeTIFF ;
 const CFStringRef  kUTTypePICT ;
 const CFStringRef  kUTTypeGIF ;
 const CFStringRef  kUTTypePNG ;
 const CFStringRef  kUTTypeQuickTimeImage ;
 const CFStringRef  kUTTypeAppleICNS
 const CFStringRef kUTTypeBMP;
 const CFStringRef  kUTTypeICO;
 */


- (void)textMyTest
{
    //    TZImagePickerController *imagePickerVc = [[TZImagePickerController alloc] initWithMaxImagesCount:9 delegate:self];
    //
    //    // You can get the photos by block, the same as by delegate.
    //    // 你可以通过block或者代理，来得到用户选择的照片.
    //
    //    [imagePickerVc setDidFinishPickingPhotosHandle:^(NSArray<UIImage *> *photos, NSArray *assets, BOOL plsy) {
    //
    //    }];
    //    [self presentViewController:imagePickerVc animated:YES completion:nil];
}


- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
}


@end
